/*
 * @Author: dadadaXU 1413107032@qq.com
 * @Date: 2025-02-14 15:26:47
 * @LastEditors: dadadaXU 1413107032@qq.com
 * @LastEditTime: 2025-02-15 16:01:16
 * @FilePath: /thread-pool/ThreadPool_pro/ThreadPool.hpp
 * @Description: 升级版的线程池
 * 1. 支持可变参模板
 * 2. 利用C++库提供的现有方法
 *  - future <=> Result
 *  - packaged_task <=> Task
 */
#ifndef THREADPOOL_HPP
#define THREADPOOL_HPP

#define THREAD_EXECUTE_LOG

#include <iostream>
#include <unordered_map>
#include <queue>
#include <memory>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <thread>
#include <future>
#include <functional>

const size_t SUBMIT_TASK_WAIT_TIME = 1; // 任务提交等待时间上限
const size_t TASK_MAX_THRESHOLD = 1024; // 任务数量上限
const size_t THREAD_MAX_THRESHOLD = 32; // 线程数量上限
const size_t THREAD_MAX_IDLE_TIME = 5;	// cached 模式线程最大空闲时间

/* 线程池工作模式 */
enum class PoolMode
{
	MODE_FIXED,	 // 固定数量的线程
	MODE_CACHED, // 线程数量可以动态增长
};

class ThreadPool
{
protected:
	ThreadPool();

public:
	/* 单例模式 */
	static ThreadPool &instance()
	{
		static ThreadPool ins;
		return ins;
	}

	~ThreadPool();

	/* 禁止拷贝构造 */
	ThreadPool(const ThreadPool &) = delete;
	ThreadPool &operator=(const ThreadPool &) = delete;
	ThreadPool(ThreadPool &&) = default;
	ThreadPool &operator=(ThreadPool &&) = default;

	/// @brief 设置线程池的工作模式
	void setMode(PoolMode mode);

	/// @brief 设置 task 任务队列上限阈值
	void setTaskQueMaxThreshHold(size_t threshHold);

	/// @brief 设置线程池 cached 模式下线程阈值
	void setThreadSizeThreshHold(size_t threshHold);

	/// @brief 给线程池提交任务 - 生产者
	/// @tparam Func 回调函数类型
	/// @tparam ...Args 函数可变参数模板
	/// @param func 线程执行的回调函数
	/// @param ...args 回调函数参数
	/// @return `std::future` 使用 `decltype` 推导出具体类型
	template <typename Func, typename... Args>
	auto submitTask(Func &&func, Args &&...args) -> std::future<decltype(func(args...))>
	{
		using ReturnType = decltype(func(args...)); // 回调函数返回值类型
		if (!checkPoolState())
		{
			std::cerr << "Thread pool closed!" << std::endl;
			/* 任务提交失败 返回对应类型的空任务 */
			return std::async(std::launch::async, []() -> ReturnType
							  { return ReturnType(); });
		}

		/* std::bind 将函数与参数绑定为一个无参函数 实现函数的无参调用 */
		auto task_ptr = std::make_shared<std::packaged_task<ReturnType()>>(
			std::bind(std::forward<Func>(func), std::forward<Args>(args)...));
		std::future<ReturnType> result = task_ptr->get_future(); // 绑定任务执行结果

		{ /* 提交任务到队列 */
			std::unique_lock<std::mutex> lock(tasksQueMtx_);
			/* 等待任务队列有空余
			 * 服务降级：用户提交任务，最长不能阻塞超过 15s，否则判断任务提交失败
			 */
			if (!notFull_.wait_for(lock,
								   std::chrono::seconds(SUBMIT_TASK_WAIT_TIME),
								   [&]() -> bool
								   { return (tasksQue_.size() < tasksQueMaxThreshHold_); }))
			{
				std::cerr << "Task queue is full, submit task timeout!" << std::endl;
				/* 任务提交失败 返回对应类型的空任务 */
				return std::async(std::launch::async, []() -> ReturnType
								  { return ReturnType(); });
			}
			/* 提交任务
			 * 伪闭包：通过中间层 void() 执行任意类型的函数 func(args...)
			 */
			tasksQue_.emplace([task_ptr]()
							  { (*task_ptr)(); });
		}
		tasksSize_++;
		notEmpty_.notify_one(); // 通知消费者

		/* cached 模式创建新线程 */
		if (poolMode_ == PoolMode::MODE_CACHED &&
			tasksSize_ > idleThreadSize_ &&
			threads_.size() < threadSizeThreshHold_)
			createThread();

		return result;
	}

	/// @brief  开启线程池
	void start(size_t initThreadSize = std::thread::hardware_concurrency());

	/// @brief  停止线程池
	void stop();

private:
	/// @brief 线程函数 从任务队列里面消费任务 - 消费者
	void threadFunc();

	/// @brief 创建新线程加入 threads_
	void createThread();

	/// @brief 检查线程池运行状态
	/// @return `true`: 运行中
	bool checkPoolState() const;

private:
	std::atomic_bool isPoolRunning_;
	PoolMode poolMode_; // 当前线程池的工作模式

	/* 线程列表 */
	std::unordered_map<std::thread::id, std::unique_ptr<std::thread>> threads_;
	size_t initThreadSize_;				  // 初始线程数量
	size_t threadSizeThreshHold_;		  // 线程数量上限
	std::atomic_uint64_t idleThreadSize_; // 记录空闲线程数量

	/* 任务队列 */
	using Task = std::function<void()>;
	std::queue<Task> tasksQue_;		 // void() 作为中间层连接任意类型的 Task
	std::atomic_uint64_t tasksSize_; // 任务数量
	size_t tasksQueMaxThreshHold_;	 // 任务队列数量上限

	std::mutex tasksQueMtx_;		   // 保证任务队列线程安全
	std::condition_variable notFull_;  // 任务队列不满
	std::condition_variable notEmpty_; // 任务队列不空

	std::condition_variable exitCond_; // 等待线程池资源全部回收
};

#endif